////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                   PEER 2 PEER FILE SHARING SYSTEM                          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
package com.cse.p2p.localfile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import com.cse.p2p.common.*;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;

/**
 *
 * @author trunghieu
 */
public abstract class LocalFile {
	
	public static final int DEFAULT_FILE_BUFFER = 256 * 1024;	// 256KB

	public static boolean isFileExist( String filename ) {
		File file = new File( filename );
		return file.exists();
	}
	
	public static boolean isPieceExist( String filename, int pieceNumber, int pieceSize ) {
		return getPiece( filename, pieceNumber, pieceSize ) != null;
	}
	
	public static byte[] getPiece( String filename, int pieceNumber, int pieceSize ) {
		try {
			File file = new File( filename );
			InputStream is = new FileInputStream( file );
			byte[] bytes = new byte[ pieceSize ];
			int i = 0;
			int length = 0;
			is.skip( pieceSize * pieceNumber );
			length = is.read( bytes );
			if ( length <= 0 ) {
				return null;
			}
			return bytes;
		}
		catch ( FileNotFoundException fEx ) {
			System.err.println( "FileNotFoundException: " );
			System.err.println( fEx.getMessage() );
			return null;
		}
		catch ( IOException ioEx ) {
			System.err.println( "IOException: " );
			System.err.print( ioEx.getMessage() );
			return null;
		}
	}
	
	public static String writeDicFiletoDisk( DicFile dicFile ) {
		throw new UnsupportedOperationException( "Not yet implemented" );
	}
	
	public static boolean writeFiletoDisk( String path, byte[] inputBytes ) {
		boolean f = true;
		try {
			File file = new File( path );
			file.getParentFile().mkdirs();
			BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream( file ) );
			bos.write( inputBytes );
			bos.close();
		}
		catch ( FileNotFoundException fnfEx ) {
			System.err.println( "ERROR: LocalFile: the file is not valid to write" );
			fnfEx.printStackTrace();
			return false;
		}
		catch ( IOException ioEx ) {
			System.err.println( "ERROR: LocalFile: the file is not valid to write" );
			ioEx.printStackTrace();
			return false;
		}
		return f;
	}
	
	public static byte[] getContentFile( File file ) {
		throw new UnsupportedOperationException( "Not yet implemented" );
	}
	
	public static String getContentDicFile( String filePath ) {
		try {
			StringBuilder text = new StringBuilder();
			BufferedReader br = new BufferedReader( new FileReader( new File( filePath ) ) );
			char[] cbuf = new char[ DEFAULT_FILE_BUFFER ];
			int readResult = 0;
			while ( ( readResult = br.read( cbuf ) ) > 0 ) {
				text.append( cbuf, 0, readResult );
			}
			br.close();
			return text.toString();
		}
		catch ( FileNotFoundException fnfEx ) {
			System.err.println( "ERROR: LocalFile: File not found when reading Dic file" );
			fnfEx.printStackTrace();
			return "";
		}
		catch ( IOException ioEx ) {
			System.err.println( "ERROR: LocalFile: IOError when reading Dic file" );
			ioEx.printStackTrace();
			return "";
		}
	}

	/**
	 * Concatenate all pieces data to a file at a specified location. The pieces
	 * data must in the temporaty files that numbered from 0 to the total number
	 * of needed pieces. If a pieces is missing, return FALSE;
	 * 
	 * @param	tempPath	The path of the <b>folder</b> contains all pieces
	 * @param	userPath	The path to the target file
	 * @return	<code>true</code> if succeed or <code>false</code> if not.
	 */
	public static boolean concatenatePiecesToFileAndCopyToUserpath( String tempPath, String userPath ) {
		boolean result = true;
		System.out.println( "Concatenating your pieces..." );
		try {
			File tmpDir = new File( tempPath );
			int numOfPieces = tmpDir.list().length;
			File targetFile = new File( userPath );
			targetFile.getParentFile().mkdirs();
			BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream( targetFile ) );
			FileInputStream fs;
			byte[] buffer = new byte[ DEFAULT_FILE_BUFFER ];
			
			for ( int p = 0; p < numOfPieces; p++ ) {
				File pieceFile = new File( tempPath + File.separatorChar + Integer.toString( p ) );
				fs = new FileInputStream( pieceFile );
				int readRes = 0;
				while ( ( readRes = fs.read( buffer ) ) > 0 ) {
					bos.write( buffer, 0, readRes );
					bos.flush();
				}
				fs.close();
			}
			bos.close();
			System.out.println( "New file created at "+targetFile.getAbsolutePath());
		}
		catch ( FileNotFoundException fnfEx ) {
			System.err.println( "ERROR: Localfile: Concate file fail, target file not found" );
			fnfEx.printStackTrace();
			return false;
		}
		catch ( IOException ioEx ) {
			System.err.println( "ERROR: Localfile: Concate file fail, read pieces data failed" );
			ioEx.printStackTrace();
			return false;
		}
		return result;
	}
}
